package ServerThreads;

import Communication.M2ServerPacket;
import Communication.S2ModulePacket;
import Communication.TaskForModule;
import Communication.TaskForServer;
import Const.ModuleConst;
import Const.ServerConst;
import LiftEngine.Lift;
import Module.ModuleClient;
import Server.ClientList;
import Server.TaskIDGetter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.SocketException;
import java.util.LinkedList;

/**
 *
 * Class description goes here.
 *
 * @author Kamil Gajowy
 */
public class SModuleCommunication extends MyThreadServer {

    private ModuleClient _me;
    private boolean needWaiting;
    private M2ServerPacket in;
    private LinkedList<TaskForServer> taskList;
    private LinkedList<TaskForModule> taskMList;
    /**
    * Default constructor.
     * @param name
     * @param cListReference
     * @param liftRef
     */

    SModuleCommunication(String name,
            ClientList cListReference,
            Lift liftRef,
            ModuleClient client,
            LinkedList<TaskForServer> tList,
            LinkedList<TaskForModule> taskMList) {
        super(name,cListReference,liftRef);
        _me = client;
        needWaiting = false;
        this.taskList = tList;
        this.taskMList = taskMList;
    }

    @Override
    public void run(){
        try {
            System.out.println("\tforked thread for new customer...");
            _me.getSocket().setSoTimeout(1000);
            synchronized(taskMList){
                send();
            }
            while (serverRunning) {
                //do stuff;
                updateModule();
            }
        } catch (SocketException ex) {
            System.out.println("@WARNING " + ex.getMessage());
        }
    }

    private void receive() {
        //System.out.print("\nreceiving...");
        try
        {
            //System.out.println("rec\t");
            ObjectInputStream ois =
                    new ObjectInputStream(_me.getSocket().getInputStream());
                Object readObject = ois.readObject();
                if ( readObject instanceof M2ServerPacket ){
                    in = (M2ServerPacket)readObject;
                    clientOperate(in);
                    //System.out.println("\tgot it");
                }
        }
        catch (ClassNotFoundException ex) {}
        catch (IOException ex) {}
    }

    private void waitForLift() {
        while(needWaiting){
            try {
                SModuleCommunication.sleep(100);
            }
            catch (InterruptedException ex) {}
        }
    }

    private void send() {
        ObjectOutputStream oos;
        S2ModulePacket packet;
        try {
            oos = new ObjectOutputStream(_me.getSocket().getOutputStream());
            //System.out.println("task count\t"+taskMList.size());
            packet = new S2ModulePacket(
                    TaskIDGetter.getInstance().getID(),
                    getLiftReference().getLiftDirection(),
                    getLiftReference().getCurrentFloor(),
                    taskMList,
                    this.getClientList(),
                    this.getLiftReference().getLastDoneID());
            oos.writeObject(packet);
            oos.flush();
        }
        catch (IOException ex) {
            System.out.println("eee \t " + ex.getMessage());
        }
    }


    private void clientOperate(M2ServerPacket inpacket) {
       //if(inpacket.getModuleType() == ModuleConst.TypeLift ) {

           //this.getLiftReference().setPacketId(inpacket.getID());


           if (inpacket.getTaskList() != null
                   && !inpacket.getTaskList().isEmpty() ){
               int i ;
               for ( i = 0 ; i < inpacket.getTaskList().size() ; ++i ){
                   System.out.println("\t\t\t iter ="+i);
                   int k = isThereSuchID(inpacket.getTaskList().get(i).getTaskID());
                   if ( k != -1 ){
                       //rewrite

                       if ( inpacket.getTaskList().get(i).getClientID() ==
                              taskList.get(k).getClientID() &&
                              inpacket.getTaskList().get(i).getActionToTake() ==
                              taskList.get(k).getActionToTake() &&
                              inpacket.getTaskList().get(i).getFloorToTravel() ==
                              taskList.get(k).getFloorToTravel()
                              ){
                           //do nothing, the same
                           System.out.println("\t\t\t ooo taki sam, ale identyczny !");
                           continue;
                       }
                       else{
                           //System.out.println("\n\t CLient ID = " + taskList.get(k).getClientID() );
                           //System.out.println("\t CLient ID P = " + inpacket.getTaskList().get(i).getClientID() );

                           //System.out.println("\t action = " + taskList.get(k).getActionToTake() );
                           //System.out.println("\t action P = " + inpacket.getTaskList().get(i).getActionToTake() );

                           //System.out.println("\t travel = " + taskList.get(k).getFloorToTravel() );
                           //System.out.println("\t travel P = " +inpacket.getTaskList().get(i).getFloorToTravel()+"\n" );

                           System.out.println("\t\t\t ooOOo mam juz taki task ! nadPISuje!");
                           taskList.set(k, inpacket.getTaskList().get(i));

                           //notify lift to update
                           //TODO not siure czy to wystarczy ? jak tak to jestem pr0 !!1
                           this.getLiftReference().setTraveling(false);
                       }
                   } else {
                       if ( inpacket.getTaskList().get(i).getTaskID() <=
                               this.getLiftReference().getLastDoneID() ){
                           System.out.println("\t\t\t uuu to jakis stary juz:( !");
                           continue;
                       }
                       System.out.println("\t\t\t nom omo mom nowiusuenki task !");
                       taskList.add(inpacket.getTaskList().get(i));
                       System.out.println("Task ID " +inpacket.getTaskList().get(i).getTaskID()
                               + "\t travel to " + inpacket.getTaskList().get(i).getFloorToTravel()
                              );
                   }
               }
           }

            int i = 0;
            int last = inpacket.getLastTaskID();
            boolean finito = false;
            while (!finito && !taskMList.isEmpty()){
                //System.out.println("i="+i+"\tsize="+taskMList.size());
                if ( taskMList.get(i).getTaskID() <= last ){
                    //System.out.println("wyjeb stare zdania wysylane DO modulu -> ID=" + taskMList.get(i).getTaskID());
                    taskMList.remove(i);
                }
                else{
                    
                    ++i;
                    if ( i >= taskMList.size() - 1){
                        finito = true;
                    }
                }
            }

            System.out.println("\n");
            for ( i = 0 ; i < taskList.size() ; ++i ){
                System.out.println("Task ID "+taskList.get(i).getTaskID()+"\t travel to " + taskList.get(i).getFloorToTravel()
                        +"\t client ID " + taskList.get(i).getClientID());
            }


      // }
    }//end client operate

    private void updateModule() {
        receive();
        //waitForLift();  //no needed
        synchronized(taskMList){
            send();
        }
    }

    private int isThereSuchID(int taskID) {
        int i;
        for ( i = 0 ; i < taskList.size() ; ++i ){
            if ( taskList.get(i).getTaskID() == taskID ){
                return i;
            }
        }

        return -1;
    }



}//end class
